home *** CD-ROM | disk | FTP | other *** search
- Subject: v09i004: ELM Mail System, Part04/19
- Newsgroups: mod.sources
- Approved: rs@mirror.TMC.COM
-
- Submitted by: Dave Taylor <hplabs!taylor>
- Mod.sources: Volume 9, Issue 4
- Archive-name: elm2/Part04
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If this archive is complete, you will see the message:
- # "End of archive 4 (of 19)."
- # Contents: Overview filter/filter.c filter/utils2.c src/aliaslib.c
- # src/edit.c src/file_utils.c src/mailtime.c src/opt_utils.c
- # src/sort.c src/syscall.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo shar: Extracting \"Overview\" \(5333 characters\)
- if test -f Overview ; then
- echo shar: Will not over-write existing file \"Overview\"
- else
- sed "s/^X//" >Overview <<'END_OF_Overview'
- X An Overview of the Elm Mail System
- X ----------------------------------
- X
- XIntroduction
- X
- X This file discusses the functionality of the Elm mail system
- Xand explains some of the motivation behind the creation and of various
- Xfeatures.
- X
- X1. What is Elm?
- X
- X Currently on Unix, there seems to be a preponderence of line-oriented
- Xsoftware. This is most unfortunate as most of the software on Unix tends to
- Xbe pretty darn hard to use! I believe that there is more than a slight
- Xcorrelation between the two, and, since I was myself having problems using
- X"mailx" with high-volume mail, I created a new mail system.
- X
- X In the lingo of the mail guru, Elm is a "User Agent" system, it's
- Xdesigned to run with "sendmail" or "/bin/rmail" (according to what's on
- Xyour system) and is a full replacement of programs like "/bin/mail" and
- X"mailx". The system is more than just a single program, however, and
- Xincludes programs like "from" to list a 'table of contents' of your
- Xmail, "printmail" to quickly paginate mail files (to allow 'clean'
- Xprintouts), and "autoreply", a systemwide daemon that can autoanswer
- Xmail for people while they're on vacation without having multiple
- Xcopies spawned on the system.
- X
- X2. What's New about Elm?
- X
- X The most significant difference between Elm and earlier mail
- Xsystems is that Elm is screen-oriented. Upon further use, however,
- Xusers will find that Elm is also quite a bit easier to use, and quite
- Xa bit more "intelligent" about sending mail and so on. For example,
- Xsay you're on "usenet" and receive a message from someone on the
- XARPANET. The sender also "cc'd" another person on ARPA. With Elm
- Xyou can simply G)roup reply and it will build the correct return
- Xaddresses.
- X
- X There are lots of subtleties like that in the program, most of
- Xwhich you'll probably find when you need them.
- X
- X3. What systems does it work on?
- X
- X Elm was originally written on HP-UX, HP's proprietary version
- Xof Bell system V, with a little BSD thrown in. Since then, it has been
- Xported to Bell, Berkeley, Sun, UTS and the Pyramid and should run on
- Xall these systems without any modifications (if there turn out to be
- Xmodifications, please notify the author as soon as possible).
- X
- X Some people have expressed interest in porting the mail system
- Xto Xenix. If it is indeed 100% system V compatible it should be rather
- Xtrivial...
- X
- X4. Does it obey existing mail standards?
- X
- X Yes! That's another of the basic reasons the program was
- Xoriginally written! To ensure that the date field, the "From:" line
- Xand so on were all added in the correct format. The program is 100%
- Xcorrect according to the RFC-822 electronic mail header protocol
- Xguide.
- X
- X5. What were the main motivating factors?
- X
- X The first two I've already mentioned, but here's a (somewhat
- Xpartial) list;
- X
- X - To have a mail system that exploited the CRT instead of
- X assuming I'm on a teletype.
- X
- X - To have a mailer that was 100% correct when dealing with
- X network mail (ie RFC-822).
- X
- X - To create a system that needed no documentation for the
- X casual user, but was still powerful enough and sophisticated
- X enough for a mail expert.
- X
- X - To write a "significant" piece of software as a learning
- X experience (I admit it!)
- X
- X - To find out how reasonable it is to try to modify a program
- X to meet the expectations of the users, rather than vice-versa.
- X
- X - To basically correct some of the dumb things that the current
- X mailers do, like letting you send mail to addresses that it
- X could trivially figure out are going to result in 'dead.letter'
- X
- X - To tie in intimately with the pathalias program output, and
- X allow users to specify machine!user or user@machine and have
- X the COMPUTER do the work of figuring out addresses...
- X
- X6. Is it reliable?
- X
- X The mailer, in various incarnations, has logged literally
- Xthousands upon thousands of hours without any problems that aren't
- Xnow corrected. As new problems arise they're dealt with in as
- Xrapid a manner as possible...
- X
- X7. What should I do now?
- X
- X The first step would be to install the mail system and have
- Xthe "elm" mailbox/alias expand to my email address (hplabs!taylor).
- XThen, once it's all up and running, drop me a line letting me know
- Xthat your site is running the system (bookkeeping) and what you and
- Xyour site think of it.
- X
- X REMEMBER: The product is evolving so if you'd like to have a
- Xsomething change, or have something new added, LET ME KNOW!!! I'd
- Xmuch rather make the change myself than start getting change reports
- Xmailed from around the world!!
- X
- X8. Disclaimers
- X
- X The author of this program will deny all liability for any
- Xdamages, either real or imagined, due to the execution of this program
- Xor anything related to either the software or the system. Furthermore,
- Xthe entire system and all source within, including the presentation
- Xscreens and commands, are legally copyrighted by the author, and while
- Xthey can be used, and abused for public domain systems, will be in
- Xviolation of the law if used in systems or programs sold for profit.
- X
- X By installing the mailer or even extracting it from the network,
- Xyou are agreeing to the above disclaimer.
- X
- X9. Finally
- X
- X I think it's a good program, and I can cite at least 75 people
- Xwho would (begrudgingly, I'm sure) agree. You should most certainly
- Xinstall the program and try it!!
- X
- X
- X -- Dave Taylor
- X
- X hplabs!taylor
- X
- XMarch 13th, 1986
- END_OF_Overview
- if test 5333 -ne `wc -c <Overview`; then
- echo shar: \"Overview\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"filter/filter.c\" \(5430 characters\)
- if test -f filter/filter.c ; then
- echo shar: Will not over-write existing file \"filter/filter.c\"
- else
- sed "s/^X//" >filter/filter.c <<'END_OF_filter/filter.c'
- X/** filter.c **/
- X
- X/** This program is used as a filter within the users ``.forward'' file
- X and allows intelligent preprocessing of mail at the point between
- X when it shows up on the machine and when it is actually put in the
- X mailbox.
- X
- X The program allows selection based on who the message is FROM, TO, or
- X what the subject is. Acceptable actions are for the program to DELETE
- X the message, SAVE the message in a specified folder, FORWARD the message
- X to a specified user, SAVE the message in a folder, but add a copy to the
- X users mailbox anyway, or simply add the message to the incoming mail.
- X
- X Filter also keeps a log of what it does as it goes along, and at the
- X end of each `quantum' mails a summary of actions, if any, to the user.
- X
- X Uses the files: $HOME/.filter for instructions to this program, and
- X $HOME/.filterlog for a list of what has been done since last summary.
- X
- X (C) Copyright 1986, Dave Taylor
- X**/
- X
- X
- X#include <stdio.h>
- X#include <pwd.h>
- X#include <ctype.h>
- X#ifdef BSD
- X# include <sys/time.h>
- X#else
- X# include <time.h>
- X#endif
- X#include <fcntl.h>
- X
- X#include "defs.h"
- X
- X#define MAIN_ROUTINE /* for the filter.h file, of course! */
- X#include "filter.h"
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X FILE *fd; /* for output to temp file! */
- X struct passwd *passwd_entry,
- X *getpwuid(); /* for /etc/passwd */
- X char filename[SLEN], /* name of the temp file */
- X buffer[LONG_SLEN]; /* input buffer space */
- X int in_header = TRUE, /* for header parsing */
- X in_to = FALSE, /* are we on 'n' line To: ? */
- X c; /* var for getopt routine */
- X
- X /* first off, let's get the info from /etc/passwd */
- X
- X if ((passwd_entry = getpwuid(getuid())) == NULL)
- X leave("Cannot get password entry for this uid!");
- X
- X strcpy(home, passwd_entry->pw_dir);
- X strcpy(username, passwd_entry->pw_name);
- X
- X gethostname(hostname, sizeof(hostname));
- X
- X /* now parse the starting arguments... */
- X
- X while ((c = getopt(argc, argv, "aclnrSsv")) > 0) {
- X switch (c) {
- X case 'a' : audible = TRUE; break;
- X case 'c' : clear_logs = TRUE; break;
- X case 'l' : log_actions_only = TRUE; break;
- X case 'r' : if (get_filter_rules() == -1)
- X fprintf(stderr,"Couldn't get rules!\n");
- X else
- X print_rules();
- X exit(0);
- X case 's' : if (get_filter_rules() == -1) exit(1);
- X show_summary(); exit(0);
- X
- X case 'S' : long_summary = TRUE;
- X show_summary(); exit(0);
- X
- X case 'n' : show_only = TRUE; break;
- X case 'v' : verbose = TRUE; break;
- X }
- X }
- X
- X if (c < 0) {
- X fprintf(stderr, "Usage: | filter [-nrv]\n\ or: filter [-c] -s\n");
- X exit(1);
- X }
- X
- X /* next, create the tempfile and save the incoming message */
- X
- X sprintf(filename, "%s.%d", filter_temp, getpid());
- X
- X if ((fd = fopen(filename,"w")) == NULL)
- X leave("Cannot open temporary file!");
- X
- X while (gets(buffer) != NULL) {
- X if (in_header) {
- X
- X if (! whitespace(buffer[0]))
- X in_to = FALSE;
- X
- X if (the_same(buffer, "From "))
- X save_from(buffer);
- X else if (the_same(buffer, "Subject:"))
- X save_subject(buffer);
- X else if (the_same(buffer, "To:")) {
- X in_to++;
- X save_to(buffer);
- X }
- X else if (the_same(buffer, "X-Filtered-By:"))
- X already_been_forwarded++; /* could be a loop here! */
- X else if (strlen(buffer) < 2)
- X in_header = 0;
- X else if (whitespace(buffer[0]) && in_to)
- X strcat(to, buffer);
- X }
- X
- X fprintf(fd, "%s\n", buffer); /* and save it regardless! */
- X fflush(fd);
- X lines++;
- X }
- X
- X fclose(fd);
- X
- X /** next let's see if the user HAS a filter file, and if so what's in
- X it (and so on) **/
- X
- X if (get_filter_rules() == -1)
- X mail_message(username);
- X else {
- X switch (action_from_ruleset()) {
- X
- X case DELETE : if (verbose)
- X printf("%sfilter (%s): Message deleted\n",
- X BEEP, username);
- X log(DELETE); break;
- X
- X case SAVE : if (save_message(rules[rule_choosen].argument2)) {
- X mail_message(username);
- X log(FAILED_SAVE);
- X }
- X else
- X log(SAVE); break;
- X
- X case SAVECC : if (save_message(rules[rule_choosen].argument2))
- X log(FAILED_SAVE);
- X else
- X log(SAVECC);
- X mail_message(username); break;
- X
- X case FORWARD: mail_message(rules[rule_choosen].argument2);
- X log(FORWARD); break;
- X
- X case EXEC : execute(rules[rule_choosen].argument2);
- X log(EXEC); break;
- X
- X case LEAVE : mail_message(username);
- X log(LEAVE); break;
- X }
- X }
- X
- X (void) unlink(filename); /* remove the temp file, please! */
- X exit(0);
- X}
- X
- Xsave_from(buffer)
- Xchar *buffer;
- X{
- X /** save the SECOND word of this string as FROM **/
- X
- X register int i, j;
- X
- X for (i=0; buffer[i] != ' '; i++) ; /* get to word */
- X
- X for (i++, j=0; buffer[i] != ' ' && i < strlen(buffer); i++)
- X from[j++] = buffer[i]; /* copy it and */
- X
- X from[j++] = '\0'; /* Null terminate! */
- X}
- X
- Xsave_subject(buffer)
- Xchar *buffer;
- X{
- X /** save all but the word "Subject:" for the subject **/
- X
- X register int skip = 8; /* skip "Subject:" initially */
- X
- X while (buffer[skip] == ' ') skip++;
- X
- X strcpy(subject, (char *) buffer + skip);
- X}
- X
- Xsave_to(buffer)
- Xchar *buffer;
- X{
- X /** save all but the word "To:" for the to list **/
- X
- X register int skip = 3; /* skip "To:" initially */
- X
- X while (buffer[skip] == ' ') skip++;
- X
- X strcpy(to, (char *) buffer + skip);
- X}
- END_OF_filter/filter.c
- if test 5430 -ne `wc -c <filter/filter.c`; then
- echo shar: \"filter/filter.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"filter/utils2.c\" \(4993 characters\)
- if test -f filter/utils2.c ; then
- echo shar: Will not over-write existing file \"filter/utils2.c\"
- else
- sed "s/^X//" >filter/utils2.c <<'END_OF_filter/utils2.c'
- X/** utils2.c **/
- X
- X/** More miscellanous utilities for the filter program and such...
- X
- X (C) Copyright 1986, Dave Taylor
- X**/
- X
- X#include <stdio.h>
- X
- X#ifdef BSD
- X# include <pwd.h>
- X#endif
- X
- X#ifdef NEED_GETHOSTNAME
- X# include <sys/utsname.h>
- X#endif
- X
- X#ifdef NEED_GETHOSTNAME
- X
- Xgethostname(hostname,size) /* get name of current host */
- Xint size;
- Xchar *hostname;
- X{
- X /** Return the name of the current host machine. UTS only **/
- X
- X /** This routine compliments of Scott McGregor at the HP
- X Corporate Computing Center **/
- X
- X int uname();
- X struct utsname name;
- X
- X (void) uname(&name);
- X (void) strncpy(hostname,name.nodename,size-1);
- X hostname[size] = '\0';
- X
- X}
- X
- X#endif
- X
- X#ifdef BSD
- X
- X/** some supplementary string functions for Berkeley Unix systems **/
- X
- Xstrspn(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns the length of the substring of
- X 'source' (starting at zero) that consists ENTIRELY of
- X characters from 'keys'. This is used to skip over a
- X defined set of characters with parsing, usually.
- X **/
- X
- X register int loc = 0, key_index = 0;
- X
- X while (source[loc] != '\0') {
- X key_index = 0;
- X while (keys[key_index] != source[loc])
- X if (keys[key_index++] == '\0')
- X return(loc);
- X loc++;
- X }
- X
- X return(loc);
- X}
- X
- Xstrcspn(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns the length of the substring of
- X 'source' (starting at zero) that consists entirely of
- X characters NOT from 'keys'. This is used to skip to a
- X defined set of characters with parsing, usually.
- X NOTE that this is the opposite of strspn() above
- X **/
- X
- X register int loc = 0, key_index = 0;
- X
- X while (source[loc] != '\0') {
- X key_index = 0;
- X while (keys[key_index] != '\0')
- X if (keys[key_index++] == source[loc])
- X return(loc);
- X loc++;
- X }
- X
- X return(loc);
- X}
- X
- Xchar *strtok(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns a pointer to the next word in source
- X with the string considered broken up at the characters
- X contained in 'keys'. Source should be a character pointer
- X when this routine is first called, then NULL subsequently.
- X When strtok has exhausted the source string, it will
- X return NULL as the next word.
- X
- X WARNING: This routine will DESTROY the string pointed to
- X by 'source' when first invoked. If you want to keep the
- X string, make a copy before using this routine!!
- X **/
- X
- X register int last_ch;
- X static char *sourceptr;
- X char *return_value;
- X
- X if (source != NULL)
- X sourceptr = source;
- X
- X if (*sourceptr == '\0')
- X return(NULL); /* we hit end-of-string last time!? */
- X
- X sourceptr += strspn(sourceptr, keys); /* skip leading crap */
- X
- X if (*sourceptr == '\0')
- X return(NULL); /* we've hit end-of-string */
- X
- X last_ch = strcspn(sourceptr, keys); /* end of good stuff */
- X
- X return_value = sourceptr; /* and get the ret */
- X
- X sourceptr += last_ch; /* ...value */
- X
- X if (*sourceptr != '\0') /* don't forget if we're at END! */
- X sourceptr++; /* and skipping for next time */
- X
- X return_value[last_ch] = '\0'; /* ..ending right */
- X
- X return((char *) return_value); /* and we're outta here! */
- X}
- X
- Xchar *strchr(buffer, ch)
- Xchar *buffer, ch;
- X{
- X /** Returns a pointer to the first occurance of the character
- X 'ch' in the specified string or NULL if it doesn't occur **/
- X
- X char *address;
- X
- X address = buffer;
- X
- X while (*address != ch) {
- X if (*address == '\0')
- X return (NULL);
- X address++;
- X }
- X
- X return ( (char *) address);
- X}
- X
- X#endif
- X
- X#ifndef NULL
- X# define NULL 0
- X#endif
- X
- X#define DONE 0
- X#define ERROR -1
- X
- Xchar *optional_arg; /* optional argument as we go */
- Xint opt_index; /* argnum + 1 when we leave */
- X
- Xint _indx = 1, _argnum = 1;
- X
- Xint
- Xgetopt(argc, argv, options)
- Xint argc;
- Xchar *argv[], *options;
- X{
- X /** Returns the character argument next, and optionally instantiates
- X "argument" to the argument associated with the particular option
- X **/
- X
- X char *word, *strchr();
- X
- X if (_argnum >= argc) { /* quick check first - no arguments! */
- X opt_index = argc;
- X return(DONE);
- X }
- X
- X if (_indx >= strlen(argv[_argnum]) && _indx > 1) {
- X _argnum++;
- X _indx = 1; /* zeroeth char is '-' */
- X }
- X
- X if (_argnum >= argc) {
- X opt_index = _argnum; /* no more args */
- X return(DONE);
- X }
- X
- X if (argv[_argnum][0] != '-') {
- X opt_index = _argnum;
- X return(DONE);
- X }
- X
- X word = strchr(options, argv[_argnum][_indx++]);
- X
- X if (word == NULL)
- X return(ERROR); /* Sun compatibility */
- X
- X if (word == NULL || strlen(word) == 0)
- X return(ERROR);
- X
- X if (word[1] == ':') {
- X
- X /** Two possibilities - either tailing end of this argument or the
- X next argument in the list **/
- X
- X if (_indx < strlen(argv[_argnum])) { /* first possibility */
- X optional_arg = (char *) (argv[_argnum] + _indx);
- X _argnum++;
- X _indx = 1;
- X }
- X else { /* second choice */
- X if (++_argnum >= argc)
- X return(ERROR); /* no argument!! */
- X
- X optional_arg = (char *) argv[_argnum++];
- X _indx = 1;
- X }
- X }
- X
- X return((int) word[0]);
- X}
- END_OF_filter/utils2.c
- if test 4993 -ne `wc -c <filter/utils2.c`; then
- echo shar: \"filter/utils2.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/aliaslib.c\" \(4735 characters\)
- if test -f src/aliaslib.c ; then
- echo shar: Will not over-write existing file \"src/aliaslib.c\"
- else
- sed "s/^X//" >src/aliaslib.c <<'END_OF_src/aliaslib.c'
- X/** aliaslib.c **/
- X
- X/** Library of functions dealing with the alias system...
- X
- X (C) Copyright 1986 Dave Taylor
- X **/
- X
- X#include "headers.h"
- X
- Xchar *expand_group(), *get_alias_address(), *expand_system();
- Xchar *get_token(), *strpbrk();
- Xlong lseek();
- X
- Xchar *get_alias_address(name, mailing, depth)
- Xchar *name;
- Xint mailing, depth;
- X{
- X /** return the line from either datafile that corresponds
- X to the specified name. If 'mailing' specified, then
- X fully expand group names. Depth specifies the nesting
- X depth - the routine should always initially be called
- X with this equal 0. Returns NULL if not found **/
- X
- X static char buffer[VERY_LONG_STRING];
- X int loc;
- X
- X if (strlen(name) == 0)
- X return( (char *) NULL);
- X
- X if (! read_in_aliases) {
- X read_alias_files();
- X read_in_aliases = TRUE;
- X }
- X
- X if (user_files)
- X if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
- X lseek(user_data, user_hash_table[loc].byte, 0L);
- X get_line(user_data, buffer);
- X if (buffer[0] == '!' && mailing)
- X return(expand_group(buffer, depth));
- X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
- X#ifdef DONT_TOUCH_ADDRESSES
- X return((char *) buffer);
- X#else
- X return(expand_system(buffer, TRUE));
- X#endif
- X else
- X return((char *) buffer);
- X }
- X
- X if (system_files)
- X if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
- X lseek(system_data, system_hash_table[loc].byte, 0L);
- X get_line(system_data, buffer);
- X if (buffer[0] == '!' && mailing)
- X return(expand_group(buffer, depth));
- X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
- X#ifdef DONT_TOUCH_ADDRESSES
- X return((char *) buffer);
- X#else
- X return(expand_system(buffer, TRUE));
- X#endif
- X else
- X return((char *) buffer);
- X }
- X
- X return( (char *) NULL);
- X}
- X
- Xchar *expand_system(buffer, show_errors)
- Xchar *buffer;
- Xint show_errors;
- X{
- X /** This routine will check the first machine name in the given path
- X (if any) and expand it out if it is an alias...if not, it will
- X return what it was given. If show_errors is false, it won't
- X display errors encountered...
- X **/
- X
- X dprint2(6, "expand_system(%s, show-errors=%s)\n", buffer,
- X onoff(show_errors));
- X findnode(buffer, show_errors);
- X
- X return( (char *) buffer);
- X}
- X
- Xchar *expand_group(members, depth)
- Xchar *members;
- Xint depth;
- X{
- X /** Given a group of names separated by commas, this routine
- X will return a string that is the full addresses of each
- X member separated by spaces. Depth is an internal counter
- X that keeps track of the depth of nesting that the routine
- X is in...it's for the get_token routine! **/
- X
- X static char buffer[VERY_LONG_STRING];
- X char buf[LONG_STRING], *word, *address, *bufptr;
- X char *strcpy();
- X
- X strcpy(buf, members); /* parameter safety! */
- X if (depth == 0) buffer[0] = '\0'; /* nothing in yet! */
- X bufptr = (char *) buf; /* grab the address */
- X depth++; /* one deeper! */
- X
- X while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
- X if ((address = get_alias_address(word, 1, depth)) == NULL) {
- X if (! valid_name(word)) {
- X dprint2(3, "Encountered illegal address %s (%s)\n",
- X word, "expand_group");
- X error1("%s is an illegal address!", word);
- X return( (char *) NULL);
- X }
- X else if (strcmp(buffer, word) != 0)
- X sprintf(buffer, "%s%s%s", buffer,
- X (strlen(buffer) > 0)? ", ":"", word);
- X }
- X else if (strcmp(buffer, address) != 0)
- X sprintf(buffer,"%s%s%s", buffer,
- X (strlen(buffer) > 0)? ", ":"", address);
- X
- X bufptr = NULL;
- X }
- X
- X return( (char *) buffer);
- X}
- X
- Xint
- Xfind(word, table, size)
- Xchar *word;
- Xstruct alias_rec table[];
- Xint size;
- X{
- X /** find word and return loc, or -1 **/
- X register int loc;
- X
- X if (strlen(word) > 20) {
- X dprint2(3, "Too long alias name entered [%s] (%s)\n", word, "find");
- X error1("Bad alias name: %s. Too long.\n", word);
- X return(-1);
- X }
- X
- X loc = hash_it(word, size);
- X
- X while (strcmp(word, table[loc].name) != 0) {
- X if (table[loc].name[0] == '\0')
- X return(-1);
- X loc = (loc + 1) % size;
- X }
- X
- X return(loc);
- X}
- X
- Xint
- Xhash_it(string, table_size)
- Xchar *string;
- Xint table_size;
- X{
- X /** compute the hash function of the string, returning
- X it (mod table_size) **/
- X
- X register int i, sum = 0;
- X
- X for (i=0; string[i] != '\0'; i++)
- X sum += (int) string[i];
- X
- X return(sum % table_size);
- X}
- X
- Xget_line(fd, buffer)
- Xint fd;
- Xchar *buffer;
- X{
- X /* Read from file fd. End read upon reading either
- X EOF or '\n' character (this is where it differs
- X from a straight 'read' command!) */
- X
- X register int i= 0;
- X char ch;
- X
- X while (read(fd, &ch, 1) > 0)
- X if (ch == '\n' || ch == '\r') {
- X buffer[i] = 0;
- X return;
- X }
- X else
- X buffer[i++] = ch;
- X}
- END_OF_src/aliaslib.c
- if test 4735 -ne `wc -c <src/aliaslib.c`; then
- echo shar: \"src/aliaslib.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/edit.c\" \(5274 characters\)
- if test -f src/edit.c ; then
- echo shar: Will not over-write existing file \"src/edit.c\"
- else
- sed "s/^X//" >src/edit.c <<'END_OF_src/edit.c'
- X/** edit.c **/
- X
- X/** This routine is for allowing the user to edit their current mailbox
- X as they wish.
- X
- X (C) Copyright 1986 Dave Taylor
- X**/
- X
- X#include "headers.h"
- X#include <errno.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- Xextern int errno;
- X
- Xchar *error_name(), *error_description(), *strcpy();
- Xlong bytes();
- Xunsigned long sleep();
- X
- Xedit_mailbox()
- X{
- X /** Allow the user to edit their mailbox, always resynchronizing
- X afterwards. Due to intense laziness on the part of the
- X programmer, this routine will invoke $EDITOR on the entire
- X file. The mailer will ALWAYS resync on the mailbox file
- X even if nothing has changed since, not unreasonably, it's
- X hard to figure out what occurred in the edit session...
- X
- X Also note that if the user wants to edit their incoming
- X mailbox they'll actually be editing the tempfile that is
- X an exact copy. More on how we resync in that case later
- X in this code.
- X **/
- X
- X FILE *real_mailbox, *temp_mailbox;
- X char filename[SLEN], buffer[LONG_SLEN], temp_infile[SLEN];
- X struct stat stat_buffer;
- X int loaded_stat_buffer = FALSE;
- X
- X PutLine0(LINES-1,0,"invoking editor...");
- X
- X if (mbox_specified == 0) {
- X sprintf(filename, "%s%s", temp_mbox, username);
- X chown(filename, userid, groupid); /* make sure we can! */
- X }
- X else
- X strcpy(filename, infile);
- X
- X /** now get and save the ownership and permissions... **/
- X
- X if (stat(infile, &stat_buffer)) {
- X error("Warning: couldn't 'stat' file, perms might get mangled");
- X sleep(2);
- X }
- X else
- X loaded_stat_buffer = TRUE;
- X
- X sprintf(buffer, "%s %s", alternative_editor, filename);
- X
- X Raw(OFF);
- X
- X if (system_call(buffer, SH) != 0) {
- X error1("Problems invoking editor %s!", alternative_editor);
- X Raw(ON);
- X sleep(2);
- X return(0);
- X }
- X
- X Raw(ON);
- X
- X if (mbox_specified == 0) { /* uh oh... now the toughie... */
- X
- X sprintf(temp_infile, "%s%s.temp", mailhome, username);
- X unlink(temp_infile); /* remove it if it's there... */
- X
- X if (bytes(infile) != mailfile_size) {
- X
- X /* SIGH. We've received mail since we invoked the editor
- X on the mailbox. We'll have to do some strange stuff to
- X remedy the problem... */
- X
- X PutLine0(LINES, 0, "Warning: new mail received...");
- X CleartoEOLN();
- X
- X if ((temp_mailbox = fopen(filename, "a")) == NULL) {
- X dprint2(1, "Attempt to open %s to append failed! (%s)\n",
- X filename, "edit_mailbox");
- X set_error("Couldn't reopen tempfile. Edit LOST!");
- X return(1);
- X }
- X /** Now let's lock the mailbox up and stream the new stuff
- X into the temp file... **/
- X
- X lock(OUTGOING);
- X if ((real_mailbox = fopen(infile, "r")) == NULL) {
- X dprint2(1,
- X "Attempt to open %s for reading new mail failed! (%s)\n",
- X infile, "edit_mailbox");
- X sprintf(buffer, "Couldn't open %s for reading! Edit LOST!",
- X infile);
- X set_error(buffer);
- X unlock();
- X return(1);
- X }
- X if (fseek(real_mailbox, mailfile_size, 0) != 0) {
- X dprint2(1, "Couldn't seek to end of infile (offset %ld) (%s)\n",
- X mailfile_size, "edit_mailbox");
- X set_error("Couldn't seek to end of mailbox. Edit LOST!");
- X unlock();
- X return(1);
- X }
- X
- X /** Now we can finally stream the new mail into the tempfile **/
- X
- X while (fgets(buffer, LONG_SLEN, real_mailbox) != NULL)
- X fprintf(temp_mailbox, "%s", buffer);
- X
- X fclose(real_mailbox);
- X fclose(temp_mailbox);
- X }
- X else
- X lock(OUTGOING); /* create a lock file if we're replacing mailbox */
- X
- X /** link to the temporary mailbox in the mailhome directory... **/
- X
- X if (link(filename, temp_infile) != 0)
- X if (errno == EXDEV) { /* attempt to link across file systems */
- X if (copy(filename, temp_infile) != 0) {
- X error("Couldn't copy temp file to mailbox!");
- X unlock(); /* ciao!*/
- X emergency_exit();
- X }
- X }
- X else {
- X Write_to_screen("\n\rCouldn't link %s to mailfile %s...\n\r",2,
- X filename, temp_infile);
- X Write_to_screen("** %s - %s **\n\r", 2,
- X error_name(errno), error_description(errno));
- X emergency_exit();
- X }
- X
- X /*** G U L P ... let's remove the incoming mail file... ***/
- X
- X unlink(infile);
- X
- X /** and quickly now... **/
- X
- X if (link(temp_infile, infile) != 0) {
- X Write_to_screen(
- X "\n\rCouldn't internally link %s to mailfile %s...\n\r",
- X 2, temp_infile, infile);
- X Write_to_screen(
- X "\n\rYou'll need to check out %s for your mail...\n\r",
- X 1, temp_infile);
- X Write_to_screen("** %s - %s **\n\r", 2,
- X error_name(errno), error_description(errno));
- X emergency_exit();
- X }
- X
- X /** And let's remove the lock file! We're DONE!!! **/
- X
- X unlock();
- X unlink(temp_infile); /* remove the temp file too */
- X unlink(filename); /* remove the temp file too */
- X error("edit changes incorporated into new mail...");
- X }
- X else
- X error("Resynchronizing with new version of mailbox...");
- X
- X sleep(2);
- X resync();
- X
- X current = 1; /* don't leave the user hanging! */
- X
- X /** finally restore the permissions... **/
- X
- X if (loaded_stat_buffer) { /* if not, it's junk! */
- X chown(infile, stat_buffer.st_uid, stat_buffer.st_gid);
- X chmod(infile, stat_buffer.st_mode);
- X }
- X
- X return(1);
- X}
- END_OF_src/edit.c
- if test 5274 -ne `wc -c <src/edit.c`; then
- echo shar: \"src/edit.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/file_utils.c\" \(5169 characters\)
- if test -f src/file_utils.c ; then
- echo shar: Will not over-write existing file \"src/file_utils.c\"
- else
- sed "s/^X//" >src/file_utils.c <<'END_OF_src/file_utils.c'
- X/** file_utils.c **/
- X
- X/** File oriented utility routines for ELM
- X
- X (C) Copyright 1986 Dave Taylor
- X**/
- X
- X#include "headers.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <ctype.h>
- X#include <errno.h>
- X
- X#ifdef BSD
- X# undef tolower
- X#endif
- X
- X#include <signal.h>
- X#include <errno.h>
- X
- X#ifdef BSD
- X# include <sys/wait.h>
- X#endif
- X
- Xextern int errno; /* system error number */
- X
- Xchar *error_name(), *error_description(), *strcpy(), *getlogin();
- X
- Xlong
- Xbytes(name)
- Xchar *name;
- X{
- X /** return the number of bytes in the specified file. This
- X is to check to see if new mail has arrived.... **/
- X
- X int ok = 1;
- X extern int errno; /* system error number! */
- X struct stat buffer;
- X
- X if (stat(name, &buffer) != 0)
- X if (errno != 2) {
- X dprint2(1,"Error: errno %s on fstat of file %s (bytes)\n",
- X error_name(errno), name);
- X Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
- X 1, name);
- X Write_to_screen("** %s - %s **\n\r", 2, error_name(errno),
- X error_description(errno));
- X emergency_exit();
- X }
- X else
- X ok = 0;
- X
- X return(ok ? (long) buffer.st_size : 0L);
- X}
- X
- Xint
- Xcan_access(file, mode)
- Xchar *file;
- Xint mode;
- X{
- X /** returns ZERO iff user can access file or "errno" otherwise **/
- X
- X int the_stat = 0, pid, w;
- X void _exit(), exit();
- X#ifdef BSD
- X union wait status;
- X#else
- X int status;
- X#endif
- X register int (*istat)(), (*qstat)();
- X
- X#ifdef NO_VM /* machine without virtual memory!! */
- X if ((pid = fork()) == 0) {
- X#else
- X if ((pid = vfork()) == 0) {
- X#endif
- X setgid(groupid);
- X setuid(userid); /** back to normal userid **/
- X
- X errno = 0;
- X
- X if (access(file, mode) == 0)
- X _exit(0);
- X else
- X _exit(errno != 0? errno : 1); /* never return zero! */
- X _exit(127);
- X }
- X
- X istat = signal(SIGINT, SIG_IGN);
- X qstat = signal(SIGQUIT, SIG_IGN);
- X
- X while ((w = wait(&status)) != pid && w != -1)
- X ;
- X
- X#ifdef BSD
- X the_stat = status.w_retcode;
- X#else
- X the_stat = status;
- X#endif
- X
- X signal(SIGINT, istat);
- X signal(SIGQUIT, qstat);
- X
- X return(the_stat);
- X}
- X
- Xint
- Xcan_open(file, mode)
- Xchar *file, *mode;
- X{
- X /** Returns 0 iff user can open the file. This is not
- X the same as can_access - it's used for when the file might
- X not exist... **/
- X
- X FILE *fd;
- X int the_stat = 0, pid, w;
- X void _exit(), exit();
- X#ifdef BSD
- X union wait status;
- X#else
- X int status;
- X#endif
- X register int (*istat)(), (*qstat)();
- X
- X#ifdef NO_VM /* machine without virtual memory!! */
- X if ((pid = fork()) == 0) {
- X#else
- X if ((pid = vfork()) == 0) {
- X#endif
- X setgid(groupid);
- X setuid(userid); /** back to normal userid **/
- X errno = 0;
- X if ((fd = fopen(file, mode)) == NULL)
- X _exit(errno);
- X else {
- X fclose(fd); /* don't just LEAVE it! */
- X _exit(0);
- X }
- X _exit(127);
- X }
- X
- X istat = signal(SIGINT, SIG_IGN);
- X qstat = signal(SIGQUIT, SIG_IGN);
- X
- X while ((w = wait(&status)) != pid && w != -1)
- X ;
- X
- X#ifdef BSD
- X the_stat = status.w_retcode;
- X#else
- X the_stat = status;
- X#endif
- X
- X signal(SIGINT, istat);
- X signal(SIGQUIT, qstat);
- X
- X return(the_stat);
- X}
- X
- Xint
- Xcopy(from, to)
- Xchar *from, *to;
- X{
- X /** this routine copies a specified file to the destination
- X specified. Non-zero return code indicates that something
- X dreadful happened! **/
- X
- X FILE *from_file, *to_file;
- X char buffer[VERY_LONG_STRING];
- X
- X if ((from_file = fopen(from, "r")) == NULL) {
- X dprint1(1,"Error: could not open %s for reading (copy)\n", from);
- X error1("could not open file %s", from);
- X return(1);
- X }
- X
- X if ((to_file = fopen(to, "w")) == NULL) {
- X dprint1(1,"Error: could not open %s for writing (copy)\n", to);
- X error1("could not open file %s", to);
- X return(1);
- X }
- X
- X while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
- X fputs(buffer, to_file);
- X
- X fclose(from_file);
- X fclose(to_file);
- X
- X return(0);
- X}
- X
- Xint
- Xappend(fd, filename)
- XFILE *fd;
- Xchar *filename;
- X{
- X /** This routine appends the specified file to the already
- X open file descriptor.. Returns non-zero if fails. **/
- X
- X FILE *my_fd;
- X char buffer[VERY_LONG_STRING];
- X
- X if ((my_fd = fopen(filename, "r")) == NULL) {
- X dprint1(1,"Error: could not open %s for reading (append)\n", filename);
- X return(1);
- X }
- X
- X while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
- X fputs(buffer, fd);
- X
- X fclose(my_fd);
- X
- X return(0);
- X}
- X
- Xcheck_mailfile_size()
- X{
- X /** Check to ensure we have mail. Only used with the '-z'
- X starting option. **/
- X
- X char filename[SLEN], *getlogin();
- X struct stat buffer;
- X
- X strcpy(username,getlogin());
- X if (strlen(username) == 0)
- X cuserid(username);
- X
- X sprintf(filename,"%s%s", mailhome, username);
- X
- X if (stat(filename, &buffer) == -1) {
- X printf(" You have no mail.\n");
- X exit(0);
- X }
- X else if (buffer.st_size < 2) { /* maybe one byte??? */
- X printf("You have no mail to read.\n");
- X exit(0);
- X }
- X}
- X
- Xcreate_readmsg_file()
- X{
- X /** Creates the file ".current" in the users home directory
- X for use with the "readmsg" program.
- X **/
- X
- X FILE *fd;
- X char buffer[SLEN];
- X
- X sprintf(buffer,"%s/%s", home, readmsg_file);
- X
- X if ((fd = fopen (buffer, "w")) == NULL) {
- X dprint3(1,"Error: couldn't create file %s - error %s (%s)\n",
- X buffer, error_name(errno), "create_readmsg_file");
- X return; /* no error to user */
- X }
- X
- X fprintf(fd, "%d\n", header_table[current-1].index_number);
- X fclose(fd);
- X}
- END_OF_src/file_utils.c
- if test 5169 -ne `wc -c <src/file_utils.c`; then
- echo shar: \"src/file_utils.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/mailtime.c\" \(4749 characters\)
- if test -f src/mailtime.c ; then
- echo shar: Will not over-write existing file \"src/mailtime.c\"
- else
- sed "s/^X//" >src/mailtime.c <<'END_OF_src/mailtime.c'
- X/** mailtime.c **/
- X
- X/** This set of routines is used to figure out when the user last read
- X their mail and to also figure out if a given message is new or not.
- X
- X (C) Copyright 1986 Dave Taylor
- X**/
- X
- X#include "headers.h"
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#ifdef BSD
- X# ifndef BSD4.1
- X# include <sys/time.h>
- X# else
- X# include <time.h>
- X# include <sys/timeb.h>
- X# endif
- X#else
- X# include <time.h>
- X#endif
- X
- Xresolve_received(entry)
- Xstruct header_rec *entry;
- X{
- X /** Entry has the data for computing the time and date the
- X message was received. Fix it and return **/
- X
- X switch (tolower(entry->month[0])) {
- X case 'j' : if (tolower(entry->month[1]) == 'a')
- X entry->received.month = JANUARY;
- X else if (tolower(entry->month[2]) == 'n')
- X entry->received.month = JUNE;
- X else
- X entry->received.month = JULY;
- X break;
- X case 'f' : entry->received.month = FEBRUARY;
- X break;
- X case 'm' : if (tolower(entry->month[2]) == 'r')
- X entry->received.month = MARCH;
- X else
- X entry->received.month = MAY;
- X break;
- X case 'a' : if (tolower(entry->month[1]) == 'p')
- X entry->received.month = APRIL;
- X else
- X entry->received.month = AUGUST;
- X break;
- X case 's' : entry->received.month = SEPTEMBER;
- X break;
- X case 'o' : entry->received.month = OCTOBER;
- X break;
- X case 'n' : entry->received.month = NOVEMBER;
- X break;
- X case 'd' : entry->received.month = DECEMBER;
- X break;
- X }
- X
- X sscanf(entry->day, "%d", &(entry->received.day));
- X
- X sscanf(entry->year, "%d", &(entry->received.year));
- X if (entry->received.year > 100) entry->received.year -= 1900;
- X
- X sscanf(entry->time, "%d:%d", &(entry->received.hour),
- X &(entry->received.minute));
- X}
- X
- Xget_mailtime()
- X{
- X /** Instantiate the values of the last_read_mail stat
- X variable based on the file access time/date of the
- X file mailtime_file. IF the file doesn't exist,
- X then assume all mail is new. **/
- X
- X struct stat buffer;
- X struct tm *timebuf;
- X char filename[SLEN];
- X#ifdef BSD
- X extern struct tm *localtime();
- X#endif
- X
- X sprintf(filename, "%s/%s", home, mailtime_file);
- X
- X if (stat(filename, &buffer) == -1) {
- X last_read_mail.month = 0;
- X last_read_mail.day = 0;
- X last_read_mail.year = 0;
- X last_read_mail.hour = 0;
- X last_read_mail.minute = 0;
- X }
- X else { /* stat okay... */
- X timebuf = (struct tm *) localtime(&(buffer.st_mtime));
- X
- X last_read_mail.month = timebuf->tm_mon;
- X last_read_mail.day = timebuf->tm_mday;
- X last_read_mail.year = timebuf->tm_year;
- X last_read_mail.hour = timebuf->tm_hour;
- X last_read_mail.minute = timebuf->tm_min;
- X }
- X}
- X
- Xupdate_mailtime()
- X{
- X /** This routine updates the last modified time of the
- X .last_read_mail file in the users home directory.
- X If the file doesn't exist, it creates it!! **/
- X
- X char filename[SLEN];
- X
- X#ifdef BSD
- X# ifdef BSD4.1
- X struct timeb loc_time;
- X time_t tval;
- X# else
- X struct timeval tval[2];
- X struct timezone tzone;
- X# endif
- X#endif
- X
- X sprintf(filename, "%s/%s", home, mailtime_file);
- X
- X#ifdef BSD
- X# ifdef BSD4.1
- X tval = (time_t) time((long *) 0);
- X if (utime(filename, &tval) == -1)
- X# else
- X gettimeofday(&tval[0], &tzone);
- X gettimeofday(&tval[1], &tzone);
- X
- X if (utimes(filename, tval) == -1) /* note the "S" */
- X# endif
- X#else
- X if (utime(filename, NULL) == -1) /* note no "S" */
- X#endif
- X /** That's what I like about programming for BSD & USG - the easy
- X portability between 'em. Especially the section 2 calls!! **/
- X
- X (void) creat(filename, 0777);
- X}
- X
- Xnew_msg(entry)
- Xstruct header_rec entry;
- X{
- X /** Return true if the current message is NEW. This can be
- X easily tested by seeing 1) if we're reading the incoming
- X mailbox and then, if so, 2) if the received_on_machine
- X date is more recent than the last_read_mail date.
- X **/
- X
- X if (mbox_specified != 0) return(FALSE); /* not incoming */
- X
- X /** Two tests - if received is OLDER than last read mail, then
- X immediately return FALSE. If received is NEWER than last
- X read mail then immediately return TRUE **/
- X
- X if (entry.received.year < last_read_mail.year)
- X return(FALSE);
- X
- X if (entry.received.year > last_read_mail.year)
- X return(TRUE);
- X
- X if (entry.received.month < last_read_mail.month)
- X return(FALSE);
- X
- X if (entry.received.month > last_read_mail.month)
- X return(TRUE);
- X
- X if (entry.received.day < last_read_mail.day)
- X return(FALSE);
- X
- X if (entry.received.day > last_read_mail.day)
- X return(TRUE);
- X
- X if (entry.received.hour < last_read_mail.hour)
- X return(FALSE);
- X
- X if (entry.received.hour > last_read_mail.hour)
- X return(TRUE);
- X
- X if (entry.received.minute < last_read_mail.minute)
- X return(FALSE);
- X
- X return(TRUE);
- X}
- END_OF_src/mailtime.c
- if test 4749 -ne `wc -c <src/mailtime.c`; then
- echo shar: \"src/mailtime.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/opt_utils.c\" \(5098 characters\)
- if test -f src/opt_utils.c ; then
- echo shar: Will not over-write existing file \"src/opt_utils.c\"
- else
- sed "s/^X//" >src/opt_utils.c <<'END_OF_src/opt_utils.c'
- X/** opt_utils.c **/
- X
- X/** This file contains routines that might be needed for the various
- X machines that the mailer can run on. Please check the Makefile
- X for more help and/or information.
- X
- X (C) Copyright 1986 Dave Taylor
- X**/
- X
- X#include <stdio.h>
- X#include "headers.h"
- X
- X#ifdef BSD
- X# include <pwd.h>
- X#endif
- X
- X#ifdef NEED_GETHOSTNAME
- X# include <sys/utsname.h>
- X#endif
- X
- X#ifdef UTS
- X# include <sys/tubio.h>
- X# define TTYIN 0 /* standard input */
- X#endif
- X
- X#ifdef NEED_GETHOSTNAME
- X
- Xgethostname(hostname,size) /* get name of current host */
- Xint size;
- Xchar *hostname;
- X{
- X /** Return the name of the current host machine. UTS only **/
- X
- X /** This routine compliments of Scott McGregor at the HP
- X Corporate Computing Center **/
- X
- X int uname();
- X struct utsname name;
- X
- X (void) uname(&name);
- X (void) strncpy(hostname,name.nodename,size-1);
- X hostname[size] = '\0';
- X
- X}
- X
- X#endif
- X
- X#ifdef UTS
- X
- Xint
- Xisa3270()
- X{
- X /** Returns TRUE and sets LINES and COLUMNS to the correct values
- X for an Amdahl (IBM) tube screen, or returns FALSE if on a normal
- X terminal (of course, next to a 3270, ANYTHING is normal!!) **/
- X
- X struct tubiocb tubecb;
- X
- X dprint0(3,"Seeing if we're a 3270...");
- X
- X if (ioctl(TTYIN, TUBGETMOD, &tubecb) == -1) {
- X dprint0(3,"We're not!\n");
- X return(FALSE); /* not a tube! */
- X }
- X
- X LINES = tubecb->line_cnt - 1;
- X COLUMNS = tubecb->col_cnt;
- X
- X dprint2(3,"We are! %d lines and %d columns!\n",
- X LINES, COLUMNS);
- X return(TRUE);
- X}
- X
- X#endif /* def UTS */
- X
- X#ifdef BSD
- X
- Xcuserid(uname)
- Xchar *uname;
- X{
- X /** Added for compatibility with Bell systems, this is the last-ditch
- X attempt to get the users login name, after getlogin() fails. It
- X instantiates "uname" to the name of the user...
- X **/
- X
- X struct passwd *password_entry, *getpwuid();
- X
- X password_entry = getpwuid(getuid());
- X
- X strcpy(uname, password_entry->pw_name);
- X}
- X
- X/** some supplementary string functions for Berkeley Unix systems **/
- X
- Xstrspn(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns the length of the substring of
- X 'source' (starting at zero) that consists ENTIRELY of
- X characters from 'keys'. This is used to skip over a
- X defined set of characters with parsing, usually.
- X **/
- X
- X register int loc = 0, key_index = 0;
- X
- X while (source[loc] != '\0') {
- X key_index = 0;
- X while (keys[key_index] != source[loc])
- X if (keys[key_index++] == '\0')
- X return(loc);
- X loc++;
- X }
- X
- X return(loc);
- X}
- X
- Xstrcspn(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns the length of the substring of
- X 'source' (starting at zero) that consists entirely of
- X characters NOT from 'keys'. This is used to skip to a
- X defined set of characters with parsing, usually.
- X NOTE that this is the opposite of strspn() above
- X **/
- X
- X register int loc = 0, key_index = 0;
- X
- X while (source[loc] != '\0') {
- X key_index = 0;
- X while (keys[key_index] != '\0')
- X if (keys[key_index++] == source[loc])
- X return(loc);
- X loc++;
- X }
- X
- X return(loc);
- X}
- X
- Xchar *strtok(source, keys)
- Xchar *source, *keys;
- X{
- X /** This function returns a pointer to the next word in source
- X with the string considered broken up at the characters
- X contained in 'keys'. Source should be a character pointer
- X when this routine is first called, then NULL subsequently.
- X When strtok has exhausted the source string, it will
- X return NULL as the next word.
- X
- X WARNING: This routine will DESTROY the string pointed to
- X by 'source' when first invoked. If you want to keep the
- X string, make a copy before using this routine!!
- X **/
- X
- X register int last_ch;
- X static char *sourceptr;
- X char *return_value;
- X
- X if (source != NULL)
- X sourceptr = source;
- X
- X if (*sourceptr == '\0')
- X return(NULL); /* we hit end-of-string last time!? */
- X
- X sourceptr += strspn(sourceptr, keys); /* skip leading crap */
- X
- X if (*sourceptr == '\0')
- X return(NULL); /* we've hit end-of-string */
- X
- X last_ch = strcspn(sourceptr, keys); /* end of good stuff */
- X
- X return_value = sourceptr; /* and get the ret */
- X
- X sourceptr += last_ch; /* ...value */
- X
- X if (*sourceptr != '\0') /* don't forget if we're at END! */
- X sourceptr++; /* and skipping for next time */
- X
- X return_value[last_ch] = '\0'; /* ..ending right */
- X
- X return((char *) return_value); /* and we're outta here! */
- X}
- X
- Xchar *strpbrk(source, keys)
- Xchar *source, *keys;
- X{
- X /** Returns a pointer to the first character of source that is any
- X of the specified keys, or NULL if none of the keys are present
- X in the source string.
- X **/
- X
- X register int loc = 0, key_index = 0;
- X
- X while (source[loc] != '\0') {
- X key_index = 0;
- X while (keys[key_index] != '\0')
- X if (keys[key_index++] == source[loc])
- X return((char *) (source + loc));
- X loc++;
- X }
- X
- X return(NULL);
- X}
- X
- Xchar *strchr(buffer, ch)
- Xchar *buffer, ch;
- X{
- X /** Returns a pointer to the first occurance of the character
- X 'ch' in the specified string or NULL if it doesn't occur **/
- X
- X char *address;
- X
- X address = buffer;
- X
- X while (*address != ch) {
- X if (*address == '\0')
- X return (NULL);
- X address++;
- X }
- X
- X return ( (char *) address);
- X}
- X
- X#endif
- END_OF_src/opt_utils.c
- if test 5098 -ne `wc -c <src/opt_utils.c`; then
- echo shar: \"src/opt_utils.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/sort.c\" \(4826 characters\)
- if test -f src/sort.c ; then
- echo shar: Will not over-write existing file \"src/sort.c\"
- else
- sed "s/^X//" >src/sort.c <<'END_OF_src/sort.c'
- X/** sort.c **/
- X
- X/** Sort mailbox header table by the field specified in the global
- X variable "sortby"...if we're sorting by something other than
- X the default SENT_DATE, also put some sort of indicator on the
- X screen.
- X
- X (C) Copyright 1986, Dave Taylor
- X**/
- X
- X#include "headers.h"
- X
- Xchar *sort_name();
- Xvoid qsort();
- X
- Xsort_mailbox(entries, visible)
- Xint entries, visible;
- X{
- X /** Sort the header_table definitions... If 'visible', then
- X put the status lines etc **/
- X
- X int last_index = -1;
- X int compare_headers(); /* for sorting */
- X
- X dprint1(2,"\n** sorting mailbox by %s **\n\n", sort_name(FULL));
- X
- X if (entries > 0)
- X last_index = header_table[current-1].index_number;
- X
- X if (entries > 30 && visible)
- X error1("sorting messages by %s", sort_name(FULL));
- X
- X qsort(header_table, (unsigned) entries, sizeof (struct header_rec),
- X compare_headers);
- X
- X if (last_index > -1)
- X find_old_current(last_index);
- X
- X clear_error();
- X}
- X
- Xint
- Xcompare_headers(first, second)
- Xstruct header_rec *first, *second;
- X{
- X /** compare two headers according to the sortby value.
- X
- X Sent Date uses a routine to compare two dates,
- X Received date is keyed on the file offsets (think about it)
- X Sender uses the truncated from line, same as "build headers",
- X and size and subject are trivially obvious!!
- X **/
- X
- X char from1[SLEN], from2[SLEN]; /* sorting buffers... */
- X int sign = 1;
- X
- X if (sortby < 0)
- X sign = -1;
- X
- X switch (abs(sortby)) {
- X
- X case SENT_DATE : return( sign*compare_dates(first, second));
- X
- X case RECEIVED_DATE: return( sign*
- X compare_parsed_dates(first->received,
- X second->received));
- X
- X case SENDER : tail_of(first->from, from1, TRUE);
- X tail_of(second->from, from2, TRUE);
- X return( sign*strcmp(from1, from2));
- X
- X case SIZE : return( sign*(first->lines - second->lines));
- X
- X case SUBJECT : /* need some extra work 'cause of STATIC buffers */
- X strcpy(from1, shift_lower(first->subject));
- X return(
- X sign*strcmp(from1, shift_lower(second->subject)));
- X
- X case STATUS : return( sign*(first->status - second->status));
- X }
- X
- X return(0); /* never get this! */
- X}
- X
- Xchar *sort_name(type)
- Xint type;
- X{
- X /** return the name of the current sort option...
- X type can be "FULL", "SHORT" or "PAD"
- X **/
- X int pad, abr;
- X
- X pad = (type == PAD);
- X abr = (type == SHORT);
- X
- X if (sortby < 0) {
- X switch (- sortby) {
- X case SENT_DATE : return(
- X pad? "Reverse Date Mail Sent " :
- X abr? "Reverse-Sent" :
- X "Reverse Date Mail Sent");
- X case RECEIVED_DATE: return(
- X abr? "Reverse-Received":
- X "Reverse Date Mail Rec'vd");
- X case SENDER : return(
- X pad? "Reverse Message Sender " :
- X abr? "Reverse-From":
- X "Reverse Message Sender");
- X case SIZE : return(
- X abr? "Reverse-Lines" :
- X "Reverse Lines in Message");
- X case SUBJECT : return(
- X pad? "Reverse Message Subject " :
- X abr? "Reverse-Subject" :
- X "Reverse Message Subject");
- X case STATUS : return(
- X pad? "Reverse Message Status " :
- X abr? "Reverse-Status":
- X "Reverse Message Status");
- X }
- X }
- X else {
- X switch (sortby) {
- X case SENT_DATE : return(
- X pad? "Date Mail Sent " :
- X abr? "Sent" :
- X "Date Mail Sent");
- X case RECEIVED_DATE: return(
- X pad? "Date Mail Rec'vd " :
- X abr? "Received" :
- X "Date Mail Rec'vd");
- X case SENDER : return(
- X pad? "Message Sender " :
- X abr? "From" :
- X "Message Sender");
- X case SIZE : return(
- X pad? "Lines in Message " :
- X abr? "Lines" :
- X "Lines in Message");
- X case SUBJECT : return(
- X pad? "Message Subject " :
- X abr? "Subject" :
- X "Message Subject");
- X case STATUS : return(
- X pad? "Message Status " :
- X abr? "Status" :
- X "Message Status");
- X }
- X }
- X
- X return("*UNKNOWN-SORT-PARAMETER*");
- X}
- X
- Xfind_old_current(index)
- Xint index;
- X{
- X /** Set current to the message that has "index" as it's
- X index number. This is to track the current message
- X when we resync... **/
- X
- X register int i;
- X
- X dprint1(2,"find-old-current(%d)\n", index);
- X
- X for (i = 0; i < message_count; i++)
- X if (header_table[i].index_number == index) {
- X current = i+1;
- X dprint1(2,"\tset current to %d!\n", current);
- X return;
- X }
- X
- X dprint1(2,"\tcouldn't find current index. Current left as %d\n",
- X current);
- X return; /* can't be found. Leave it alone, then */
- X}
- END_OF_src/sort.c
- if test 4826 -ne `wc -c <src/sort.c`; then
- echo shar: \"src/sort.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: Extracting \"src/syscall.c\" \(5245 characters\)
- if test -f src/syscall.c ; then
- echo shar: Will not over-write existing file \"src/syscall.c\"
- else
- sed "s/^X//" >src/syscall.c <<'END_OF_src/syscall.c'
- X/** syscall.c **/
- X
- X/** These routines are used for user-level system calls, including the
- X '!' command and the '|' commands...
- X
- X (C) Copyright 1986 Dave Taylor
- X**/
- X
- X#include "headers.h"
- X
- X#include <signal.h>
- X
- X#ifdef BSD
- X# include <sys/wait.h>
- X#endif
- X
- Xchar *argv_zero();
- Xvoid _exit();
- X
- Xint
- Xsubshell()
- X{
- X /** spawn a subshell with either the specified command
- X returns non-zero if screen rewrite needed
- X **/
- X
- X char command[SLEN];
- X int ret;
- X
- X PutLine0(LINES-3,COLUMNS-40,"(use the shell name for a shell)");
- X PutLine0(LINES-2,0,"Shell Command: ");
- X command[0] = '\0';
- X (void) optionally_enter(command, LINES-2, 15, FALSE);
- X if (strlen(command) == 0) {
- X MoveCursor(LINES-2,0); CleartoEOLN();
- X return(0);
- X }
- X
- X MoveCursor(LINES,0); CleartoEOLN();
- X Raw(OFF);
- X if (cursor_control) transmit_functions(OFF);
- X
- X ret = system_call(command, USER_SHELL);
- X
- X PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
- X
- X Raw(ON);
- X (void) getchar();
- X if (cursor_control) transmit_functions(ON);
- X
- X if (ret != 0) error1("Return code was %d", ret);
- X return(1);
- X}
- X
- Xsystem_call(string, shell_type)
- Xchar *string;
- Xint shell_type;
- X{
- X /** execute 'string', setting uid to userid... **/
- X /** if shell-type is "SH" /bin/sh is used regardless of the
- X users shell setting. Otherwise, "USER_SHELL" is sent **/
- X
- X int stat = 0, pid, w;
- X#ifdef BSD
- X union wait status;
- X#else
- X int status;
- X#endif
- X register int (*istat)(), (*qstat)();
- X
- X dprint2(2,"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
- X string);
- X
- X#ifdef NO_VM /* machine without virtual memory! */
- X if ((pid = fork()) == 0) {
- X#else
- X if ((pid = vfork()) == 0) {
- X#endif
- X setgid(groupid); /* and group id */
- X setuid(userid); /* back to the normal user! */
- X
- X if (strlen(shell) > 0 && shell_type == USER_SHELL) {
- X execl(shell, argv_zero(shell), "-c", string, (char *) 0);
- X }
- X else
- X execl("/bin/sh", "sh", "-c", string, (char *) 0);
- X _exit(127);
- X }
- X
- X istat = signal(SIGINT, SIG_IGN);
- X qstat = signal(SIGQUIT, SIG_IGN);
- X
- X while ((w = wait(&status)) != pid && w != -1)
- X ;
- X
- X#ifdef BSD
- X if (status.w_retcode != 0) stat = status.w_retcode;
- X#else
- X if (w == -1) stat = status;
- X#endif
- X
- X signal(SIGINT, istat);
- X signal(SIGQUIT, qstat);
- X
- X return(stat);
- X}
- X
- Xint
- Xdo_pipe()
- X{
- X /** pipe the tagged messages to the specified sequence.. **/
- X
- X char command[SLEN], buffer[LONG_SLEN], message_list[SLEN];
- X register int ret, tagged = 0, i;
- X
- X message_list[0] = '\0'; /* NULL string to start... */
- X
- X for (i=0; i < message_count; i++)
- X if (ison(header_table[i].status, TAGGED)) {
- X sprintf(message_list,"%s %d", message_list,
- X header_table[i].index_number);
- X tagged++;
- X }
- X
- X if (tagged > 1)
- X PutLine0(LINES-2,0,"Pipe tagged msgs to: ");
- X else if (tagged)
- X PutLine0(LINES-2,0,"Pipe tagged msg to : ");
- X else {
- X PutLine0(LINES-2,0,"Pipe current msg to: ");
- X sprintf(message_list,"%d", header_table[current-1].index_number);
- X }
- X
- X command[0] = '\0';
- X
- X (void) optionally_enter(command, LINES-2, 21, FALSE);
- X if (strlen(command) == 0) {
- X MoveCursor(LINES-2,0); CleartoEOLN();
- X return(0);
- X }
- X
- X MoveCursor(LINES,0); CleartoEOLN();
- X Raw(OFF);
- X
- X if (cursor_control) transmit_functions(OFF);
- X
- X sprintf(buffer, "%s -f %s -h %s | %s",
- X readmsg,
- X infile,
- X message_list,
- X command);
- X
- X ret = system_call(buffer, USER_SHELL);
- X
- X PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
- X Raw(ON);
- X (void) getchar();
- X if (cursor_control) transmit_functions(ON);
- X
- X if (ret != 0) error1("Return code was %d", ret);
- X return(1);
- X}
- X
- Xprintmsg()
- X{
- X /** Print current message or tagged messages using 'printout'
- X variable. Error message iff printout not defined! **/
- X
- X char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
- X char message_list[SLEN];
- X register int retcode, tagged = 0, i;
- X
- X if (strlen(printout) == 0) {
- X error("Don't know how to print - option \"printmail\" undefined!");
- X return;
- X }
- X
- X message_list[0] = '\0'; /* reset to null... */
- X
- X for (i=0; i < message_count; i++)
- X if (header_table[i].status & TAGGED) {
- X sprintf(message_list, "%s %d", message_list,
- X header_table[i].index_number);
- X tagged++;
- X }
- X
- X if (! tagged)
- X sprintf(message_list," %d", header_table[current-1].index_number);
- X
- X sprintf(filename,"%s%d", temp_print, getpid());
- X
- X if (in_string(printout, "%s"))
- X sprintf(printbuffer, printout, filename);
- X else
- X sprintf(printbuffer, "%s %s", printout, filename);
- X
- X sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
- X readmsg, infile, message_list,
- X filename,
- X printbuffer);
- X
- X dprint0(2,"Printing system call...\n");
- X
- X Centerline(LINES, "queueing...");
- X
- X if ((retcode = system_call(buffer, SH)) == 0) {
- X sprintf(buffer, "Message%s queued up to print", plural(tagged));
- X Centerline(LINES, buffer);
- X }
- X else
- X error1("Printout failed with return code %d", retcode);
- X
- X unlink(filename); /* remove da temp file! */
- X}
- X
- Xlist_folders()
- X{
- X /** list the folders in the users FOLDERHOME directory. This is
- X simply a call to "ls -C"
- X **/
- X
- X char buffer[SLEN];
- X
- X CleartoEOS(); /* don't leave any junk on the bottom of the screen */
- X sprintf(buffer, "cd %s;ls -C", folders);
- X printf("\n\rContents of your folder directory:\n\r\n\r");
- X system_call(buffer, SH);
- X printf("\n\r");
- X}
- X
- END_OF_src/syscall.c
- if test 5245 -ne `wc -c <src/syscall.c`; then
- echo shar: \"src/syscall.c\" unpacked with wrong size!?
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 4 \(of 19\).
- cp /dev/null ark4isdone
- DONE=true
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- echo shar: You still need to run archive ${I}.
- DONE=false
- fi
- done
- if test "$DONE" = "true" ; then
- echo You have unpacked all 19 archives.
- echo "See the Instructions file"
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- fi
- ## End of shell archive.
- exit 0
-